package com.example;

import java.lang.management.ManagementFactory;
import java.lang.management.MemoryPoolMXBean;
import java.lang.management.MemoryUsage;
import java.util.ArrayList;
import java.util.List;

/**
 * Survivor区演示程序
 * 展示UseAdaptiveSizePolicy如何影响Survivor区大小
 */
public class SurvivorDemo {
    
    // 存储对象的列表
    private static List<Object> objects = new ArrayList<>();
    
    public static void main(String[] args) throws InterruptedException {
        System.out.println("Survivor区大小变化演示程序");
        System.out.println("JVM参数: -Xms1536m -Xmx1536m -Xmn512m");
        System.out.println("请分别使用以下参数运行观察区别:");
        System.out.println("1. 默认启用UseAdaptiveSizePolicy");
        System.out.println("2. 禁用: -XX:-UseAdaptiveSizePolicy");
        System.out.println("==========================================");
        
        // 打印初始内存池信息
        printMemoryPoolInfo();
        
        // 模拟高并发对象创建场景
        simulateHighLoadScenario();
    }
    
    /**
     * 模拟高并发对象创建场景
     */
    private static void simulateHighLoadScenario() throws InterruptedException {
        System.out.println("开始模拟高并发对象创建场景...");
        
        long startTime = System.currentTimeMillis();
        int totalCount = 0;
        
        while (System.currentTimeMillis() - startTime < 120000) { // 运行2分钟
            // 快速创建大量小对象
            createObjectsBatch(10000);
            totalCount += 10000;
            
            // 偶尔清理一部分对象（模拟GC）
            if (totalCount % 50000 == 0) {
                cleanupObjects();
                System.out.println("已创建对象总数: " + totalCount + ", 清理后剩余: " + objects.size());
                
                // 打印当前内存池信息
                printMemoryPoolInfo();
            }
            
            Thread.sleep(100); // 短暂休眠
        }
        
        System.out.println("演示完成，总共创建对象: " + totalCount);
    }
    
    /**
     * 批量创建对象
     */
    private static void createObjectsBatch(int count) {
        for (int i = 0; i < count; i++) {
            // 创建不同大小的对象
            if (i % 100 == 0) {
                // 1%的大对象
                objects.add(new byte[1024 * 8]); // 8KB
            } else {
                // 99%的小对象
                objects.add(new byte[64 + (i % 256)]); // 64B-319B
            }
        }
    }
    
    /**
     * 清理部分对象（模拟GC）
     */
    private static void cleanupObjects() {
        // 保留最新的10000个对象
        if (objects.size() > 10000) {
            objects = new ArrayList<>(objects.subList(objects.size() - 10000, objects.size()));
        }
    }
    
    /**
     * 打印内存池信息
     */
    private static void printMemoryPoolInfo() {
        System.out.println("--- 内存池信息 ---");
        List<MemoryPoolMXBean> pools = ManagementFactory.getMemoryPoolMXBeans();
        
        for (MemoryPoolMXBean pool : pools) {
            String name = pool.getName();
            // 只关注年轻代相关的内存池
            if (name.contains("Eden") || name.contains("Survivor") || name.contains("Young")) {
                MemoryUsage usage = pool.getUsage();
                if (usage != null) {
                    System.out.printf("%s: %s/%s (%.1f%%)%n", 
                        name,
                        formatBytes(usage.getUsed()),
                        formatBytes(usage.getCommitted()),
                        usage.getCommitted() > 0 ? (double) usage.getUsed() / usage.getCommitted() * 100 : 0
                    );
                    
                    // 特别关注Survivor区
                    if (name.contains("Survivor")) {
                        System.out.println("  >>> Survivor区使用情况: " + 
                            formatBytes(usage.getUsed()) + "/" + formatBytes(usage.getCommitted()));
                    }
                }
            }
        }
        System.out.println("------------------\n");
    }
    
    /**
     * 格式化字节数
     */
    private static String formatBytes(long bytes) {
        if (bytes < 1024) return bytes + "B";
        if (bytes < 1024 * 1024) return String.format("%.1fKB", bytes / 1024.0);
        if (bytes < 1024 * 1024 * 1024) return String.format("%.1fMB", bytes / (1024.0 * 1024));
        return String.format("%.1fGB", bytes / (1024.0 * 1024 * 1024));
    }
}